#include <stdio.h>
#include <string.h>
#include <disp_manager.h>

// disp_manager.c中一定是不涉及直接对Framebuffer操作的代码的
// disp_manager.c一定是对DispOpr进行操作

static struct DispOpr *g_DispDevs = NULL;
static struct DispOpr *g_DispDefault = NULL;
static DispBuff g_tDispBuff;
static int line_width;
static int pixel_width;


// 将一个字体的位图数据ptFontBitMap以dwColor色绘制到缓冲区
void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor)
{
    int i, j, p, q;
	// 区域起点：定义显示区域的左上角
	int x = ptFontBitMap->tRegion.iLeftUpX; // 区域左上角x坐标
	int y = ptFontBitMap->tRegion.iLeftUpY; // 区域左上角y坐标
	int width = ptFontBitMap->tRegion.iWidth;
	int heigh = ptFontBitMap->tRegion.iHeigh;
	// 区域边界：定义显示区域的右下角
	int x_max = x + width;
    int y_max = y + heigh;

	// 声明一块buffer用来放位图数据
	unsigned char *buffer = ptFontBitMap->pPixelDatas;

	// q和p遍历字体位图数据，而i和j遍历显示区域 (Region)
    for ( j = y, q = 0; j < y_max; j++, q++ )  // j 和 q 遍历区域的每一行
    {
        for ( i = x, p = 0; i < x_max; i++, p++ )  // i 和 p 遍历区域的每一列
        {
            // 如果当前像素在屏幕范围内，才进行绘制
            if ( i < 0 || j < 0 || i >= g_tDispBuff.iXres || j >= g_tDispBuff.iYres )
                continue;

            // 如果字体位图中该像素非零，说明该像素需要绘制
            if (buffer[q * width + p])
			{
				PutPixel(i, j, dwColor); // 在显示区域绘制该像素
			}
		}
    }
}


// 在ptRegion区域以dwColor颜色居中渲染name字符串
void DrawTextInRegionCentral(char *name, PRegion ptRegion, unsigned int dwColor)
{	
	int iOriginX, iOriginY;
	int error;
	int i = 0;
	FontBitMap tFontBitMap;

	// 计算合适的字体大小
	int n = strlen(name);
	int iFontSize = ptRegion->iWidth / n / 2;
	if (iFontSize > ptRegion->iHeigh)
		{
			iFontSize =  ptRegion->iHeigh;
		}

	// 计算渲染的起点
	iOriginX = (ptRegion->iWidth - n * iFontSize)/2 + ptRegion->iLeftUpX;
	iOriginY = (ptRegion->iHeigh - iFontSize)/2 + iFontSize + ptRegion->iLeftUpY;

	SetFontSize(iFontSize);

	while (name[i])
	{
		/* get bitmap */
		tFontBitMap.iCurOriginX = iOriginX;
		tFontBitMap.iCurOriginY = iOriginY;
		error = GetFontBitMap(name[i], &tFontBitMap);
		if (error)
		{
			printf("GetFontBitMap err\n");
			return;
		}

		/* draw on buffer */		
		DrawFontBitMap(&tFontBitMap, dwColor);		

		iOriginX = tFontBitMap.iNextOriginX;
		iOriginY = tFontBitMap.iNextOriginY;	
		i++;
	}
}



// 在ptRegion绘制dwColor色的矩形
void DrawRegion(PRegion ptRegion, unsigned int dwColor)
{
    // 获取区域的起始坐标和大小
    int xStart = ptRegion->iLeftUpX;  // 区域的左上角 X 坐标
    int yStart = ptRegion->iLeftUpY;  // 区域的左上角 Y 坐标
    int width = ptRegion->iWidth;     // 区域的宽度
    int height = ptRegion->iHeigh;    // 区域的高度

    // 遍历区域的每一行（y 坐标）
    for (int y = yStart; y < yStart + height; y++)
    {
        // 遍历每一行中的每一个像素（x 坐标）
        for (int x = xStart; x < xStart + width; x++)
        {
            // 绘制当前像素
            PutPixel(x, y, dwColor);
        }
    }
}



// 将dwColor色的像素绘制到缓冲区中的(x,y)位置
int PutPixel(int x, int y, unsigned int dwColor)
{
	unsigned char *pen_8 = (unsigned char *)(g_tDispBuff.buff+y*line_width+x*pixel_width);
	unsigned short *pen_16;	
	unsigned int *pen_32;	

	unsigned int red, green, blue;	

	pen_16 = (unsigned short *)pen_8;
	pen_32 = (unsigned int *)pen_8;

	switch (g_tDispBuff.iBpp)
	{
		case 8:
		{
			*pen_8 = dwColor;
			break;
		}
		case 16:
		{
			/* 565 */
			red   = (dwColor >> 16) & 0xff;
			green = (dwColor >> 8) & 0xff;
			blue  = (dwColor >> 0) & 0xff;
			dwColor = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
			*pen_16 = dwColor;
			break;
		}
		case 32:
		{
			*pen_32 = dwColor;
			break;
		}
		default:
		{
			printf("can't surport %dbpp\n", g_tDispBuff.iBpp);
			return -1;
			break;
		}
	}

	return 0;
}



// 注册单个DispOpr到设备链表中
void RegisterDispDevice(DispOpr *ptDispOpr){

    ptDispOpr->ptNext = g_DispDevs;
    g_DispDevs = ptDispOpr;

}


/*
	<注册所有显示设备>
	1.调用外部的RegisterFBtoDeviceList
	2.RegisterFBtoDeviceList又会调用RegisterDevice函数
	将声明的g_tFramebufferOpr结构体注册到链表中
*/
int RegisterAllDispDevs(void)
{
    extern void RegisterFBtoDeviceList(void);
    RegisterFBtoDeviceList();

    // extern RegisterWebtoDeviceList(void);
    // RegisterWebtoDeviceList();
    return 0;   
}


// 在设备链表中按照name选择默认设备
int ChooseDefaultDevice(char *name)
{
	PDispOpr pTmp = g_DispDevs;
    while (pTmp)
    {
        if (strcmp(name, pTmp->name) == 0)
        {
            g_DispDefault = pTmp;
            // printf("int ChooseDefaultDevice(char *name) successed!\n");
            return 0;
        }
        pTmp = pTmp->ptNext;
    }
    
    // printf("int ChooseDefaultDevice(char *name) failed!\n");
    return -1;
}

// 初始化默认显示设备
int InitDefaultDevice(void)
{
	int ret;
	
	ret = g_DispDefault->DeviceInit();
	if (ret)
	{
		printf("DeviceInit failed.\n");
		return -1;
	}

	
	ret = g_DispDefault->GetBuffer(&g_tDispBuff);
	if (ret)
	{
		printf("GetBuffer failed.\n");
		return -1;
	}
	
	line_width  = g_tDispBuff.iXres * g_tDispBuff.iBpp/8;
	pixel_width = g_tDispBuff.iBpp/8;

	return 0;
}



// GetBuffer是对g_tDispBuff结构体中的字段值进行操作，也就是写入数据
// GetDeviceBuffer是获取整个结构体，返回指针
PDispBuff GetDeviceBuffer(void)
{
	return &g_tDispBuff;
}



// 把g_tDispBuff中的数据刷到ptRegion
int FlushDeviceRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{	
	return g_DispDefault->FlushRegion(ptRegion, ptDispBuff);
}